package com.framework.dubbo.producer.utils;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.framework.dubbo.FileSystemConfig;
import io.minio.*;
import io.minio.messages.Item;
import org.apache.commons.lang3.StringUtils;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * 描述：
 * 封装minio 工具类
 * @author xianggj
 * @Date 2021/9/9 17:48
 **/
public class MinioUtils {

    public MinioClient minioClient;

    public FileSystemConfig minioConfig;

    private static final String SLASH = "/";
    private static final String DOT = ".";
    private static final String BANK = " ";
    private static final String EMPTY = "";

    /**
     * 获取客户端
     * @param fileSystemConfig
     * @return
     */
    public MinioUtils(FileSystemConfig fileSystemConfig)  {
        MinioClient client = MinioClient.builder()
                .endpoint(fileSystemConfig.getEndpoint())
                .credentials(fileSystemConfig.getAccessKey(), fileSystemConfig.getSecretKey())
                .build();
        this.minioConfig = fileSystemConfig;
        this.minioClient =  client;
    }

    /**
     * 获取下载前缀
     * http://192.168.1.37:9000/minio/download/heneng/hn_data/finebi-wp.pdf?token=
     * @return
     */

    public String getDownLoadPrefix(){
        return minioConfig.getEndpoint() + minioConfig.getDownloadPrefix()+ minioConfig.getBucketName()
                + File.separator + minioConfig.getRunningDirs() + File.separator ;

    }


    /**
     * 自定义输入流和文件扩展名
     * @param is
     * @param ext
     * @return
     */
    public String putFile(InputStream is, String folder, String ext) {
        return putFile(folder, is, ext, ContentTypeUtil.getContentType(ext));
    }

    /**
     * 自定义输入流和文件扩展名
     * @param is
     * @param ext
     * @return
     */
    public String putFile(InputStream is, String ext) {
        return putFile( DateUtil.format(new Date(), "yyyyMMdd"), is, ext, ContentTypeUtil.getContentType(ext));
    }

    public String putSourceFile(InputStream is, String ext) {
        return putFile(minioConfig.getSourceDirs(), is, ext, ContentTypeUtil.getContentType(ext));
    }

    public String putRunningFile(InputStream is, String ext) {
        return putFile( minioConfig.getRunningDirs(), is, ext, ContentTypeUtil.getContentType(ext));
    }
    public String putTagetFile(InputStream is, String ext) {
        return putFile( minioConfig.getTargetDirs(), is, ext, ContentTypeUtil.getContentType(ext));
    }

    public String putFile(String folder, InputStream is, String ext) {
        String bucketName = minioConfig.getBucketName();
        return putFile(bucketName, folder, is, ext, ContentTypeUtil.getContentType(ext));
    }

    /**
     * 自定义输入流和文件扩展名
     * @param is
     * @param ext
     * @return
     */
    public String putFile(String folder, InputStream is, String ext, String contextType) {
        String bucketName = minioConfig.getBucketName();
        return putFile(bucketName, folder, is, ext, contextType);
    }

    /**
     * 转换路径为bucket和object
     * @param path
     * @return
     */
    public String[] pathToBucket(String path) {
        path = StringUtils.startsWith(path, SLASH)?
                StringUtils.substring(path, 1):path;
        String bucket = StrUtil.subBefore(path, SLASH, false);
        String object = StrUtil.subAfter(path, SLASH, false);
        return new String[]{bucket, object};
    }


    /**
     * 删除指定文件
     *  有时候需要保证文件唯一
     * @param path
     * @return 访问地址
     */
    public void removeFile(String path) {
        String[] baf = pathToBucket(path);
        removeFile(path, baf[0], baf[1]);

    }

    public void removeFile(String path, String bucketName, String objectName) {
        try {
            minioClient.removeObject(RemoveObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectName) .build());

        } catch (Exception e) {
            e.printStackTrace();
            //删除失败中断
            System.out.println("文件删除失败："+path);
        }
    }

    /**
     * http文件上传(增加根路径)
     * @param bucketName
     * @param folder
     * @return 访问地址
     */
    public String putFile(String bucketName,String folder,InputStream is, String ext) {
        if(!bucketExists(bucketName)) {
            createBucket(bucketName);
        }

        String uuidName = IdUtil.fastSimpleUUID() + DOT + ext;
        if (StrUtil.isNotEmpty(folder)){
            uuidName = folder.concat(SLASH).concat(uuidName);
        }
        try {
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(uuidName)
                    .stream(is, is.available(), -1)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("文件上传失败");
        }
        String url = EMPTY.concat(SLASH).concat(bucketName).concat(SLASH).concat(uuidName);
        return url;
    }

    /**
     * http文件上传(增加根路径)
     * @param bucketName
     * @param folder
     * @return 访问地址
     */
    public String putFile(String bucketName, String folder,InputStream is, String ext,
                          String contentType) {

        if(!bucketExists(bucketName)) {
            createBucket(bucketName);
        }
        String uuidName = IdUtil.fastSimpleUUID() + DOT + ext;
        if (StrUtil.isNotEmpty(folder)){
            uuidName = folder.concat(SLASH).concat(uuidName);
        }
        try {
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(uuidName)
                    .contentType(contentType)
                    .stream(is, is.available(), -1)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("文件上传失败");
        }
        String url = EMPTY.concat(SLASH).concat(bucketName).concat(SLASH).concat(uuidName);
        return url;
    }


    /**
     * 根据文件路径覆盖
     * @param path 源路径
     * @return 访问地址
     */
    public String coverFile(String path, InputStream is, String ext) {
        String[] baf = pathToBucket(path);
        removeFile(path, baf[0], baf[1]);
        try {
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(baf[0])
                    .object(baf[1])
                    .contentType(ContentTypeUtil.getContentType(ext))
                    .stream(is, is.available(), -1)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("文件上传失败");
        }
        String url = EMPTY.concat(SLASH).concat(baf[0]).concat(SLASH).concat(baf[1]);
        return url;
    }

    /**
     * copy文件夹到指定目录
     * @param dir
     * @param folder 新存储的文件夹
     * @return
     */
    public Map<String, String> uploadRunningDirs(File dir, String folder){
        Map<String, String> pathMap = new HashMap<>();
        if (dir == null ){
            return pathMap;
        }
        System.out.println("------------------");
        for (File file : dir.listFiles()) {
            if (file.isDirectory()){
                uploadRunningDirs(file, folder + SLASH + file.getName());
            } else {
                String fileName = file.getName();
                String ext = StrUtil.subAfter(fileName,DOT,true);
                String path = coverFile(minioConfig.getBucketName() + SLASH + minioConfig.getRunningDirs() +  SLASH + folder +  SLASH + fileName ,
                        FileUtil.getInputStream(file),
                        ext);
                pathMap.put(fileName, path);
            }
        }
        System.out.println("------------------");
        return pathMap;
    }

    /**
     * 获取文件流
     * @param fileName
     * @param bucketName
     * @return 访问地址
     */
    public InputStream getFileStream(String bucketName,String fileName) throws Exception {
        InputStream in = minioClient.getObject(GetObjectArgs.builder()
                .bucket(bucketName).object(fileName).build());
        return in;
    }

    public InputStream getFileStream(String path) throws Exception {
        path = StringUtils.startsWith(path, SLASH)?
                StringUtils.substring(path, 1):path;
        String bucket = StrUtil.subBefore(path, SLASH, false);
        String fileName = StrUtil.subAfter(path, SLASH, false);
        return getFileStream(bucket, fileName);
    }
    /**
     * 创建bucket
     * @param bucketName
     */
    public void createBucket(String bucketName){
        try {
            minioClient.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("创建bucket失败");
        }
    }


    /**
     * 判断文件是否存在
     *
     * @param bucketName 存储桶
     * @param objectName 对象
     * @return true：存在
     */
    public  boolean docsObjectExist(String bucketName, String objectName) {
        boolean exist = true;
        try {
            minioClient
                    .statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
        } catch (Exception e) {
            exist = false;
        }
        return exist;
    }

    public boolean docsObjectExist(String path) throws Exception {
        path = StringUtils.startsWith(path, SLASH)?
                StringUtils.substring(path, 1):path;
        String bucket = StrUtil.subBefore(path, SLASH, false);
        String fileName = StrUtil.subAfter(path, SLASH, false);
        return docsObjectExist(bucket, fileName);
    }


    /**
     * 判断文件夹是否存在
     *
     * @param bucketName 存储桶
     * @param objectName 文件夹名称（去掉/）
     * @return true：存在
     */
    public  boolean doesFolderExist(String bucketName, String objectName) {
        boolean exist = false;
        try {
            Iterable<Result<Item>> results = minioClient.listObjects(
                    ListObjectsArgs.builder().bucket(bucketName).prefix(objectName).recursive(false).build());
            for (Result<Item> result : results) {
                Item item = result.get();
                if (item.isDir() && objectName.equals(item.objectName())) {
                    exist = true;
                }
            }
        } catch (Exception e) {
            exist = false;
        }
        return exist;
    }

    /**
     * 判断文件是否存在是否存在
     */
    public boolean bucketExists(String bucketName){
        try {
            return minioClient.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    /**
     * 上传文本为文件
     */
    public String putText(String bucketName, String folder, String objectName,  String ext, String text) {
        if (StrUtil.isBlank(text)) {
            throw new NullPointerException("文本为空");
        }

        if (StrUtil.isBlank(bucketName)) {
            bucketName = minioConfig.getBucketName();
        }

        if (StrUtil.isBlank(objectName)) {
            objectName = IdUtil.fastSimpleUUID();
        }

        String objectPath = objectName + DOT + ext;
        if (StrUtil.isNotEmpty(folder)) {
            objectPath = folder.concat(SLASH).concat(objectPath);
        }

        try {
            ByteArrayInputStream bais = new ByteArrayInputStream(text.getBytes(StandardCharsets.UTF_8));
            minioClient.putObject(PutObjectArgs.builder()
                    .bucket(bucketName)
                    .object(objectPath)
                    .stream(bais, bais.available(), -1)
                    .build());
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("上传文件对象失败");
        }
        return EMPTY.concat(SLASH).concat(bucketName).concat(SLASH).concat(objectPath);
    }

}
